<!--
  Jeepay plus 通用表格, 支持基础分页， 检索， 自动刷新和列选择

  @author terrfly
  @site https://www.jeequan.com
  @date 2021/12/09 06:18
-->

<template>
  <div>
    <!-- 操作行： 包括了新增等按钮 和 自动刷新等操作 -->
    <div v-if="props.topRowIsShow" class="jeepay-table-top-row">
      <div class="jeepay-table-top-left">
        <!-- 插入左上角 按钮操作行 -->
        <slot name="topBtnSlot" />

        <!-- 数据统计按钮 -->
        <a-button v-if="statisticsIsShow" class="statistics" @click="statistics = !statistics">
          <i class="bi bi-bar-chart-fill" />
          <span>{{ statistics ? '关闭统计' : '数据统计' }}</span>
        </a-button>
      </div>

      <!-- 自动刷新 和 其他操作图标  flex布局 -->
      <div class="operation-icons">
        <span v-if="autoRefTableConfig" class="pd-0-20">
          <span style="margin-right:10px; color: #A9B3B1;">自动刷新：<span style="margin-right:5px; color: #000;">{{ autoRefTableSubTime }}s</span></span>
          <a-switch v-model:checked="autoRefTableBtnState" @change="autoRefTableBtnStateChangeFunc" />
        </span>

        <!-- 导出按钮 功能未实现，暂时屏蔽 -->
        <a-tooltip>
          <template #title>数据导出</template>
          <!-- <i class="bi bi-download pd-0-20" v-if="typeof (tableExportFunc) === 'function' " style="cursor: pointer; font-size: 17px;" @click="tableExportFunc" /> -->
          <download-outlined v-if="typeof (tableExportFunc) === 'function' " class="pd-0-20" style="cursor: pointer; font-size: 17px;" @click="tableExportFunc" />
        </a-tooltip>

        <!-- 表格密度 -->
        <a-dropdown class="pd-0-20" :trigger="['click']">
          <a-tooltip>
            <template #title>表格密度</template>
            <i class="bi bi-distribute-vertical" style="cursor: pointer; font-size: 16px;" />
          </a-tooltip>
          <template #overlay>
            <a-menu @click="menuHandle">
              <a-menu-item key="1">默认</a-menu-item>
              <a-menu-item key="2">宽松</a-menu-item>
              <a-menu-item key="3">紧凑</a-menu-item>
            </a-menu>
          </template>
        </a-dropdown>

        <!-- 自定义列选项 -->
        <a-dropdown v-model:visible="colDropdownVisible" class="pd-0-20" :trigger="['click']">
          <a-tooltip>
            <template #title>列设置</template>
            <i class="bi bi-layout-sidebar-inset-reverse" style="cursor: pointer; font-size: 16px;" />
          </a-tooltip>
          <template #overlay>
            <a-menu>
              <template v-for="(item, index) in tableColumns.filter( r => r.rightColMenuShow)" :key="index">
                <a-menu-item>
                  <a-checkbox v-model:checked="item.jeepayTableShow">
                    {{ item.title }}
                  </a-checkbox>
                </a-menu-item>
              </template>
            </a-menu>
          </template>
        </a-dropdown>
      </div>
    </div>
    <div v-else style="padding-top: 30px;" />

    <!-- 数据统计展示区 -->
    <div v-show="statistics" class="data-statistics" :style="{background: statisticsBack}">
      <slot name="statistics" />
    </div>
    <!-- 骨架屏 -->
    <a-skeleton v-if="skeleton" active :loading="true" style="padding:30px" :paragraph="{ rows: 6 }" />
    <!-- Table -->
    <a-table
      v-if="!skeleton"
      :data-source="apiResData.records"
      :columns="tableColumns.filter( r => r.jeepayTableShow)"
      :pagination="paginationShow ? pagination : paginationShow"
      :loading="showLoading"
      :row-selection="rowSelection"
      :row-key="rowKey"
      :scroll="{ x: 'max-content' }"
      :class="{'table-compact-density': compact, 'table-loose-density': loose}"
      :custom-row="customRow"
      @resize-column=" (w, col) => {col.width = w} "
      @change="handleTableChange"
    >
      <!-- header 标题 插槽 -->
      <template #headerCell="{ title, column }">
        <slot name="headerCell" :title="title" :column="column" />
      </template>

      <!-- body 内容 插槽 -->
      <template #bodyCell="{ text, record, index, column }">
        <slot name="bodyCell" :text="text" :record="record" :index="index" :column="column" />
      </template>

      <!-- 嵌套子表格插槽 内容 插槽 -->
      <template v-if="expandedRowShow" #expandedRowRender="{ text, record, index, column }">
        <slot name="expandedRowRender" :text="text" :record="record" :index="index" :column="column" />
      </template>
    </a-table>
  </div>
</template>

<script setup lang="ts">

import { reactive, defineProps, onMounted, nextTick, ref, onUnmounted, defineExpose, getCurrentInstance } from 'vue'
const { $hasAgentEnt } = getCurrentInstance()!.appContext.config.globalProperties

// 定义传入属性
const props = defineProps({
  columnResizable: { type: Boolean, default: true },
  tableColumns: { type: Array as () => any[],  default: () => [] },
  reqTableDataFunc: { type: Function ,default:() => {}},
  searchData: {type:Object, default: () => {}}, // 搜索条件参数
  pageSize: { type: Number, default: 10 }, // 默认每页条数
  initData: { type: Boolean, default: true }, // 初始化列表数据， 默认true
  autoRefTableConfig: { type: Object, default: null }, // {defaultOpen: true, interval: 10}
  rowSelection:{type:Object,default:null},
  rowKey: { type: [String, Function] , default: () => {}}, // 定义rowKey 如果不定义将会出现（树状结构出问题， checkbox不消失等）
  tableExportFunc: { type: Function , default: null},
  statisticsIsShow: {type: Boolean, default: false }, // 数据统计按钮是否展示
  statisticsBack: {type: String, default: '#FAFAFA' }, // 数据统计背景颜色
  scrollX: { type: Number, default: 1300 },
  expandedRowShow: { type: Boolean, default: false },
  topRowIsShow: { type: Boolean, default: true }, // 顶部操作行是否展示
  customRow: { type: Function , default: null }, // 行属性
  paginationShow: { type: Boolean , default: true }, // 分页显示
})
const emit = defineEmits(['btnLoadClose','handleTableChange'])

//自定义列选择的显示和隐藏
const colDropdownVisible = ref(false)

// 开启关闭数据统计
const statistics = ref(false)

// 自动刷新：相关参数
let autoRefTableBtnState = ref(false) //默认关闭
let autoRefTableSubTime = ref(10) //自动刷新剩余时间
let autoRefTableTimeoutObject:any = null // 自动刷新表格的setTimeOut对象，当前组件唯一

// 表单：  定义组件内变量
let iPage = { pageNumber: 1, pageSize: props.pageSize } // 默认table 分页/排序请求后端格式
let pagination = reactive({
  total: 0,
  current: 1,
  pageSize: props.pageSize,
  showSizeChanger: true,
  showTotal: (total) => `共${total}条`
}) // ATable 分页配置项
let showLoading = ref(false) // loading效果
let apiResData = reactive({ total: 0, records: [] }) // 接口返回数据

// 更改表格密度
let loose = ref(false) // 宽松
let compact = ref(false) // 紧凑
const menuHandle = ({ key }: any) => {
  if(key == 1) {
    loose.value = false
    compact.value = false
  } else if (key == 2) {
    loose.value = true
    compact.value = false
  } else {
    loose.value = false
    compact.value = true
  }
}

/**  钩子事件  **/

// 挂载事件： 处理是否显示等信息， 首次加载， 和是否显示自动刷新等的处理。
onMounted(() => {
  let tableColumns = props.tableColumns
  // 遍历全部列
  for (let i = 0; i < props.tableColumns.length; i++) {

    tableColumns[i].rightColMenuShow = true //右侧 更多列是否显示 

    // 如果明确设置了默认隐藏，那么设置为false,  当属性值为 未设置或者false时，需要设置为true
    if(typeof (tableColumns[i].defaultHidden) == 'boolean' && tableColumns[i].defaultHidden === true){
      tableColumns[i].jeepayTableShow = false // 隐藏
    }
    // 如果明确设置了代理商列， 并且当前不支持代理商
    else if(typeof (tableColumns[i].agentEntCol) == 'boolean' && tableColumns[i].agentEntCol === true && !$hasAgentEnt()){
      tableColumns[i].jeepayTableShow = false // 隐藏
      tableColumns[i].rightColMenuShow = false // 隐藏
    } else {
      tableColumns[i].jeepayTableShow = true // 默认全部显示
    }
    
    // 固定列和scroll 冲突， 当table属性设置为自动拉伸时：所有的非固定列设置为可以拉伸。  &&  最后一列不可拉伸
    if (!tableColumns[i].fixed && (i != props.tableColumns.length - 1)) {
      tableColumns[i].resizable = true // 自动添加列可拖拽效果
    }

  }

  //初始化表数据
  props.initData ? refTable(true)  : undefined

  // 包含了【自动刷新】设置项
  if(props.autoRefTableConfig){
    autoRefTableBtnState.value = props.autoRefTableConfig.defaultOpen || false
    autoRefTableSubTime.value = props.autoRefTableConfig.interval || 10
  }

  // 自动刷新
  autoRefTableBtnState.value ? autoRefTableFunc() : undefined

})

// 卸载组件 钩子事件： 需要关闭定时器等操作
onUnmounted(()=>{

  if(autoRefTableTimeoutObject){  // 关闭定时器
    clearTimeout(autoRefTableTimeoutObject)
  }
  autoRefTableBtnState.value = false
})


/**  自定义函数 ： **/

// 自动刷新 处理事件
function autoRefTableFunc(){

  if(!autoRefTableBtnState.value){
    return false
  }

  // 加载定时器
  autoRefTableTimeoutObject = setTimeout(() => {
    let subTime = autoRefTableSubTime.value - 1
    if(subTime <= 0){
      refTable(true).then(()=> {
        autoRefTableSubTime.value = props.autoRefTableConfig.interval || 10
        autoRefTableFunc()
      })
    }else{
      autoRefTableSubTime.value = subTime
      autoRefTableFunc()
    }
  }, 1000)
}

// 自动刷新按钮 变更处理函数
function autoRefTableBtnStateChangeFunc(state){

  if(state){ // 开启了自动刷新
    autoRefTableFunc()

  }else{  // 关闭了自动刷新

    if(autoRefTableTimeoutObject){ // 清除定时器
      clearTimeout(autoRefTableTimeoutObject)
    }
  }
}

  const skeleton = ref(true) // 骨架屏显示隐藏


// 查询表格数据
function refTable(isToFirst = false) {
  if (isToFirst) {
    iPage.pageNumber = 1
    pagination.current = 1
  }

  // 显示loading图标
  showLoading.value = true

  // 更新检索数据
  return props.reqTableDataFunc(Object.assign({}, iPage, props.searchData)).then((bizData) => {
        pagination.total = bizData.total // 更新总数量
        skeleton.value = false // 请求成功骨架屏隐藏
        Object.assign(apiResData, bizData) // 列表数据更新

        showLoading.value = false // 关闭loading
        // 数据为0 ，并且为当前页面没有在第一页则需要自动跳转到上一页（解决，删除第二页数据全部删除后无数据的情况 ）
        if (bizData.length === 0 && iPage.pageNumber > 1) {
          nextTick(() => {
            // 最大页码
            const maxPageNumber = bizData.total / iPage.pageSize + (bizData.total % iPage.pageSize === 0 ? 0 : 1)
            if (maxPageNumber === 0) { // 已经无数据
              return false
            }

            // 跳转到的页码
            const toPageSize = iPage.pageNumber - 1 > maxPageNumber ? maxPageNumber : iPage.pageNumber - 1
            iPage.pageNumber = toPageSize
            pagination.current = toPageSize
            refTable(false)
          })
        }
        emit('btnLoadClose')
      }).catch( () => {
        showLoading.value = false
        skeleton.value = false // 请求失败骨架屏隐藏
        emit('btnLoadClose')
      }) //取消loading
}

// 分页、排序、筛选变化时触发
function handleTableChange(paginationParams, filters, sorter) {

  // 合并响应式数据
  Object.assign(pagination, paginationParams)
  iPage = {
    pageSize: pagination.pageSize, // 每页条数
    pageNumber: pagination.current, // 当前页码
    sortField: sorter.columnKey, // 排序字段
    sortOrder: sorter.order, // 排序顺序
    ...filters // 过滤数据
  }
  emit('handleTableChange', sorter)
  refTable()
}

// 将表格事件暴露出去  https://www.jianshu.com/p/39d14c25c987
defineExpose({ refTable } )

</script>
<style lang="less">
// 数据统计按钮
.statistics {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  margin-top: 1px;
  background: @primary-glass !important;
  border: none;
  color: var(--ant-primary-color);
  // transition: 0.3s ease;
  i {
    transition: 0s;
  }
  span {
    margin-left: 5px;
  }
  &:hover {
    opacity: 0.8;
  }
}
// 数据统计区域
.data-statistics {
  margin: 0 30px 10px;
  padding: 28px 0 32px 0;
  border-radius: 3px;
  border: 1px solid #ebebeb;
  transform: translateY(-10px);
}

// 调整antdv 的table默认padding高度 同时也是默认密度
.ant-table-content {
  tr {
    td {
      padding: 8px 8px 8px 15px;
      background: #fff;
    }
  }
}

// 密度 宽松
.table-loose-density {
  tr {
    td {
      padding: 16px 8px 16px 15px !important;
    }
  }
}

// 密度 紧凑
.table-compact-density {
  tr {
    td {
      padding: 3px 8px 3px 15px !important;
    }
  }
}

.jeepay-table-top-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 30px 30px 10px 30px;

  .jeepay-table-top-left {
    display: flex;
    align-items: center;
  }
  .ant-btn {
    margin-right: 10px;
    margin-bottom: 10px;
  }

  .operation-icons {
    display: flex;
    justify-content: space-between;
    align-items: center;

    .pd-0-20 {
      padding: 0 10px;
    }
  }
}
</style>
